﻿/*
 * GLEntityBase.h
 *
 *  Created on: Jun 6, 2014
 *      Author: yuliang
 */

#ifndef GLENTITYBASE_H_
#define GLENTITYBASE_H_

#include <stdint.h>
#include <vector>
#include <map>
#include <set>

#include <common/PUtility.h>

#include "GLBaseDefine.h"
#include "GLGlobalDefine.h"

class CGLEntityBase {
public:
	/* must set */
	typedef std::set<Index_t>	SetIndex_t;
	typedef std::map<CGLEntityBase*, Index_t>	MapEntityIndex_t;
	typedef std::vector<CGLEntityBase*>	VecEntity_t;
public:
	CGLEntityBase(Type_t type, CGLEntityBase* parent = nullptr);
	virtual ~CGLEntityBase();

	// 初始化实例(创建实体后执行)
	virtual inline void Init() {}
	// 重置实例(实体使用完毕后执行)
	virtual inline void Reset();

	// 获取类型
	inline Type_t GetEntityType() const { return m_EntityType; }
	// 获取id
	inline EntityId_t GetEnityId() const { return m_EntityId; }

	// 重置状态位
	inline void ResetStatus() { m_Status = 0; }
	// 设置状态
	inline bool SetStatus(Status_t status) { return CPUtility::Set1Byte<Status_t>(m_Status, status); }
	// 移除状态
	inline bool RmStatus(Status_t status) { return CPUtility::Rm1Byte<Status_t>(m_Status, status); }
	// 是否存在状态
	inline bool ExistStatus(Status_t status) const { return CPUtility::WithThisByte<Status_t>(m_Status, status); }

	// 设置父实例
	inline void SetParent(CGLEntityBase* parent) { m_Parent = parent; }
	// 获取父实例
	inline CGLEntityBase* GetParent() const { return m_Parent; }

	// 设置子实例个数
	inline int32_t InitChildSize(uint32_t size);
	// 扩大子实例个数
	inline int32_t ExpandChildSize(uint32_t size);
	// 获取所有子实例个数(包括空实体)
	inline uint32_t GetChildSize() const { return m_Childs.size(); }
	// 获取所有子实体(包括空实体)
	inline const VecEntity_t* GetChilds() const { return &m_Childs; }
	// 获取实际子实例个数
	inline uint32_t GetRealChildSize() const { return m_ChildIds.size(); }
	// 位置是否有效
	inline bool ValidIndex(Index_t index) const { if (index >= m_Childs.size()) return false; return true; }
	// 获取实际子实体
	inline const MapEntityIndex_t* GetRealChilds() const { return &m_ChildIds; }
	// 增加一个子实例,并返回新增下标
	inline int32_t AddChild(CGLEntityBase* child);
	// 设置一个子实例,并返回设置下标
	inline int32_t SetChild(Index_t index, CGLEntityBase* child);
	// 获取某一个子实例
	inline CGLEntityBase* GetChild(Index_t index) const;
	// 是否存在子实例
	inline int32_t ExistChild(CGLEntityBase* child) const;
	// 移除某一个子实例
	inline CGLEntityBase* RmChild(Index_t index);
	inline uint32_t GetChildIndex(CGLEntityBase* entity) const;
	inline uint32_t RmChild(CGLEntityBase* entity);
	// 交换两个子实例位置
	int32_t SwapChild(Index_t first, Index_t second);
	// 获取最靠前空位置
	inline int32_t GetEmptyIndex() const;
	inline int32_t GetEmptyIndexSize() const { return m_ChildIndexs.size(); }
	inline const SetIndex_t* GetAllEmptyIndex() const { return &m_ChildIndexs; }

	// 设置附着物
	inline void SetAttachment(void* attachment) { m_Attachment = attachment; }
	// 获取附着物
	inline void* GetAttachment() const { return m_Attachment; }
private:
	Type_t m_EntityType;								// 实体基本类型
	EntityId_t m_EntityId;								// 实体id
	Status_t m_Status;									// 实体状态
	void* m_Attachment;									// 附着对象(比如任务可能在LogicServer处理,则保存此LogicServer的连接)

	CGLEntityBase* m_Parent;							// 父实体
	Index_t m_DefaultChildSize;							// 默认子实体个数
	SetIndex_t m_ChildIndexs;							// 空闲子实体位置
	VecEntity_t m_Childs;								// 子实体集合
	MapEntityIndex_t m_ChildIds;						// 真实子实体集合(用于判断是否存在)

	static EntityId_t staticEntityId;					// 自增后,赋给实体作为实体id
};

void CGLEntityBase::Reset() {
	m_Status = 0;
	m_Parent = nullptr;
	m_Attachment = nullptr;

	for (size_t i = 0; i != m_Childs.size(); ++i) {
		m_Childs[i] = nullptr;
		m_ChildIndexs.insert(i);
	}
	m_ChildIds.clear();
}

int32_t CGLEntityBase::InitChildSize(uint32_t size) {
	if (size > CHILDS_ENTITY_MAX_NUM)
		return EntityChildsTooMany;
	if (!m_Childs.empty() || 0 != m_DefaultChildSize)
		return EntityChildsNotEmpty;
	m_DefaultChildSize = size;
	for (uint32_t i = 0; i != size; ++i)
		AddChild(nullptr);
	return CommonErrnoSucceed;
}

int32_t CGLEntityBase::ExpandChildSize(uint32_t size) {
	if (m_DefaultChildSize + size > CHILDS_ENTITY_MAX_NUM)
		return EntityChildsTooMany;
	m_DefaultChildSize += size;
	for (uint32_t i = 0; i != size; ++i) {
		int32_t tRet = AddChild(nullptr);
		if (CommonErrnoSucceed < tRet)
			return tRet;
	}
	return CommonErrnoSucceed;
}

int32_t CGLEntityBase::AddChild(CGLEntityBase* child) {
	size_t tSize = m_Childs.size();
	if (0 != m_DefaultChildSize && tSize >= m_DefaultChildSize)
		return EntityChildsTooMany;
	if (tSize >= CHILDS_ENTITY_MAX_NUM)
		return EntityChildsTooMany;
	m_Childs.push_back(child);
	if (nullptr == child)
		m_ChildIndexs.insert(tSize);
	else {
		//child->SetParent(this);
		m_ChildIds[child] = tSize;
	}
	return tSize;
}

int32_t CGLEntityBase::SetChild(Index_t index, CGLEntityBase* child) {
	if (nullptr == child)
		return CommonErrnoParam;
	if (EntityExistChild == ExistChild(child))
		return EntityExistChild;
	if (index >= m_Childs.size())
		return EntityErrnoIndexNone;
	//child->SetParent(this);
	m_Childs[index] = child;
	m_ChildIds[child] = index;
	m_ChildIndexs.erase(index);
	return index;
}

CGLEntityBase* CGLEntityBase::GetChild(Index_t index) const {
	if (index >= m_Childs.size())
		return nullptr;
	return m_Childs[index];
}

int32_t CGLEntityBase::ExistChild(CGLEntityBase* child) const {
	if (m_ChildIds.find(child) != m_ChildIds.end())
		return EntityExistChild;
	return EntityNotExistChild;
}

CGLEntityBase* CGLEntityBase::RmChild(Index_t index) {
	if (index >= m_Childs.size())
		return nullptr;
	CGLEntityBase* tEntity = m_Childs[index];
	if (tEntity != nullptr) {
		m_Childs[index] = nullptr;
		m_ChildIds.erase(tEntity);
		m_ChildIndexs.insert(index);
	}
	return tEntity;
}

uint32_t CGLEntityBase::GetChildIndex(CGLEntityBase* entity) const {
	MapEntityIndex_t::const_iterator tIter = m_ChildIds.find(entity);
	if (tIter != m_ChildIds.end())
		return tIter->second;
	return EntityNotExistChild;
}

uint32_t CGLEntityBase::RmChild(CGLEntityBase* entity) {
	uint32_t tIndex = GetChildIndex(entity);
	if (tIndex != EntityNotExistChild) {
		if (nullptr != RmChild(tIndex))
			return tIndex;
	}
	return EntityNotExistChild;
}

int32_t CGLEntityBase::GetEmptyIndex() const {
	if (m_ChildIndexs.empty())
		return EntityErrnoFill;
	return *m_ChildIndexs.begin();
}

#endif /* GLENTITYBASE_H_ */
